1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Window component.

mod anchor;
mod menu;
mod options;
mod position;
mod render;

#[cfg(feature = "settings")]
mod settings;

use crate::ui::{
    render::{small_padding, window_context_menu},
    Component, Hideable, Ui, Windowable,
};
use std::ops::{Deref, DerefMut};

pub use anchor::*;
pub use menu::*;
pub use options::*;
pub use position::*;

#[cfg(feature = "settings")]
pub use settings::*;

/// Window component.
#[derive(Debug, Clone)]
pub struct Window<T> {
    /// The name (title) of the window.
    pub name: String,

    /// Inner [`Component`] responsible for rendering content.
    pub inner: T,

    /// Current window options state.
    pub options: WindowOptions,
}

impl<T> Window<T> {
    /// Creates a new window with [`WindowOptions`] and the passed [`Windowable`] component.
    pub fn new<P>(name: impl Into<String>, inner: T, options: WindowOptions) -> Self
    where
        T: Windowable<P>,
    {
        Self {
            name: name.into(),
            inner,
            options,
        }
    }

    /// Creates a new window with [`WindowOptions`] and a default [`Windowable`] component.
    pub fn with_default<P>(name: impl Into<String>, options: WindowOptions) -> Self
    where
        T: Default + Windowable<P>,
    {
        Self::new(name, T::default(), options)
    }

    /// Handles a key press event.
    ///
    /// Toggles visibility and returns `true` if the key matches the hotkey.
    #[inline]
    pub fn key_press(&mut self, key: usize) -> bool {
        self.options.key_press(key)
    }
}

impl<T> Deref for Window<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<T> DerefMut for Window<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<T, P> Component<P> for Window<T>
where
    T: Windowable<P>,
{
    fn render(&mut self, ui: &Ui, mut props: P) {
        if let Some(_window) = self.options.render_window(ui, &self.name) {
            // update options
            self.options.update(ui);

            if T::CONTEXT_MENU {
                let pos = ui.window_pos();

                // render context menu
                window_context_menu(format!("Options##{}", self.name), || {
                    let _style = small_padding(ui);

                    self.inner.render_menu(ui, &mut props);
                    if T::DEFAULT_OPTIONS {
                        window_options_menus(ui, &mut self.options, pos);
                    }
                });
            }

            // render window content
            self.inner.render(ui, props);
        }
    }
}

impl<T> Hideable for Window<T> {
    fn is_visible(&self) -> bool {
        self.options.is_visible()
    }

    fn visible_mut(&mut self) -> &mut bool {
        self.options.visible_mut()
    }
}